﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web.Caching;
using Medianamik.Client.MVP.Model.Service;
using Medianamik.Core;
using SubSonic;

namespace Medianamik.Client.MVP.Model.DataAccess
{
    public class CachedMedianamikRepository<TConcreteTypeCollection, TConcreteType, TInterface> : 
        MedianamikRepositoryBase<TConcreteTypeCollection, TConcreteType, TInterface>, IMedianamikRepository<TInterface>
        where TConcreteTypeCollection : ICollectionWithChildren<TConcreteTypeCollection, TConcreteType>, new()
        where TConcreteType : IRecordBase, new()
    {
        private const string childsKey = " Childs Of ";
        private const string parentsKey = " Parents Of ";
        private readonly IMedianamikRepository<TInterface> _repository;
        private readonly ICacheService<TInterface> _cache;
        private readonly Func<CacheDependency> _getDependency;
        private readonly CultureInfo _cultureInfo;

        public CachedMedianamikRepository(IMedianamikRepository<TInterface> repository, ICacheService<TInterface> cache, CultureInfo culture, Func<CacheDependency> getDependency)
        {
            _repository = repository;
            _cache = cache;
            _getDependency = getDependency;
            _cultureInfo = culture;
        }

        public virtual TInterface Get(Guid nodeId)
        {
            var key = _cultureInfo.Name + nodeId;
            return _cache.Get(key, _getDependency(), () => _repository.Get(nodeId));
        }

        public virtual TInterface Get(Guid nodeId, CultureInfo culture)
        {
            var key = culture.Name + nodeId;
            return _cache.Get(key, _getDependency(), () => _repository.Get(nodeId, culture));
        }

        public virtual IEnumerable<TInterface> All()
        {
            return _repository.All();
        }

        public virtual IEnumerable<TInterface> ChildsOf(Guid nodeId)
        {
            return ChildsOf(nodeId, false, 1);
        }

        public virtual IEnumerable<TInterface> ChildsOf(Guid nodeId, bool inclusive, int maxDepth)
        {
            var key = _cultureInfo.Name + childsKey + nodeId + inclusive + maxDepth;
            return _cache.GetCollection(key, _getDependency(), () => _repository.ChildsOf(nodeId, inclusive, maxDepth));
        }

        public virtual IEnumerable<TInterface> ParentsOf(Guid nodeId)
        {
            return ParentsOf(nodeId, false, 1);
        }

        public virtual IEnumerable<TInterface> ParentsOf(Guid nodeId, bool inclusive, int maxDepth)
        {
            var key = _cultureInfo.Name + parentsKey + nodeId + inclusive + maxDepth;
            return _cache.GetCollection(key, _getDependency(), () => _repository.ParentsOf(nodeId, inclusive, maxDepth));
        }

        public virtual TInterface Get(Guid nodeId, CultureInfo culture, ContentState contentState)
        {
            return _repository.Get(nodeId, culture, contentState);
        }

        public virtual TInterface Get(Guid id, ContentState contentState)
        {
            return _repository.Get(id, contentState);
        }
    }
}
